package com.ocp.macro.filter;

import com.alibaba.fastjson.JSONObject;
import com.ocp.macro.entity.UserInfoToken;
import com.ocp.macro.enums.DataCode;
import com.ocp.macro.utils.GsonUtils;
import com.ocp.macro.utils.JwtUtil;
import com.ocp.macro.utils.ResultInfoUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author Robod
 * @date 2020/8/10 7:54
 * 认证过滤器
 */
@Slf4j
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    private RedisTemplate<String, Object> redisTemplate;

    public JwtLoginFilter(AuthenticationManager authenticationManager, RedisTemplate<String, Object> redisTemplate) {
        super.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/macro/login", "POST"));
        this.authenticationManager = authenticationManager;
        this.redisTemplate = redisTemplate;
    }


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String loginType = request.getParameter("logintype");
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // json数据请求
        if (username==null|| "".equals(username) || loginType==null || "".equals(loginType)){
            JSONObject jsonObject = GsonUtils.getParameters(request);
            log.debug("request中的json数据：{}",jsonObject);
            loginType = jsonObject==null? "" : jsonObject.getString("logintype");
            username = jsonObject==null? "" : jsonObject.getString("username");
            password = jsonObject==null? "" :jsonObject.getString("password");
        }

        loginType = loginType != null? loginType.trim() : "";
        username = username != null ? username.trim() : "";
        password = password != null ? password.trim() : "";

        log.debug("登录账号：{}，登录方式：{}", username, loginType);

        if ("".equals(loginType) || "".equals(username))
            throw new UsernameNotFoundException("账户不可用");

        // RSA 解密

        username = username + "-"+ loginType;

        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        super.setDetails(request, authRequest);
        return authenticationManager.authenticate(authRequest);
    }


    @Override
    public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        /*把密码设置为null, 封装信息*/
        UserInfoToken userDetails = (UserInfoToken) authResult.getPrincipal();
        userDetails.setPassword(null);
        /*把密码设置为null, 封装信息*/

        log.info("登录成功：{}",userDetails.getUsername());

        // 生成token
        String[] tokens = JwtUtil.createToken(request, userDetails, 7, TimeUnit.DAYS);
        // redisKey 由当前认证成功的账户的username+"::"+用户浏览器信息，ip和操作系统组成
        String redisKey = userDetails.getUsername()+"::"+tokens[0];
        redisTemplate.opsForValue().set(redisKey, tokens[1]);
        redisTemplate.expire(redisKey, 7, TimeUnit.DAYS);

        response.addHeader("Authorization", userDetails.getUsername()+":"+tokens[1]);

        Map<String, Object> map = new HashMap<>();
        map.put("code", DataCode.SUCCESS.getCode());
        map.put("message", DataCode.SUCCESS.getMessage());

        ResultInfoUtils.responseData(response, map);
    }
}
